package com.googlecode.jch.plugin.creation;

import com.googlecode.jch.SolutionConfig;
import com.googlecode.jch.Tests;
import com.googlecode.jch.plugin.configuration.JCHConfiguration;
import com.googlecode.jch.plugin.templates.JCHFileTemplateProvider;
import com.intellij.ide.IdeView;
import com.intellij.ide.actions.CreateElementActionBase;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.FileTemplateUtil;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.JavaDirectoryService;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Properties;

/**
 * @author Iskander Akishev
 */
public class CreateSolutionAction extends CreateElementActionBase {
	private String inputSource;
	private String outputSource;
	private String bodyTemplateName;

	@Override
	protected boolean isAvailable(DataContext dataContext) {
		final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
		final IdeView view = LangDataKeys.IDE_VIEW.getData(dataContext);
		if (project == null || view == null || view.getDirectories().length == 0) {
			return false;
		}

		ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(project).getFileIndex();
		for (PsiDirectory dir : view.getDirectories()) {
			if (projectFileIndex.isInSourceContent(dir.getVirtualFile()) && (JavaDirectoryService.getInstance().getPackage(dir) != null)) {
				return true;
			}
		}

		return false;
	}

	@NotNull
	@Override
	protected PsiElement[] invokeDialog(Project project, PsiDirectory directory) {
	  final MyInputValidator validator = new MyInputValidator(project, directory);

	  final DialogWrapper dialog = new MyDialog(project, validator);

	  dialog.show();
	  return validator.getCreatedElements();
	}

	@Override
	protected void checkBeforeCreate(String newName, PsiDirectory directory) throws IncorrectOperationException {
		JavaDirectoryService.getInstance().checkCreateClass(directory, newName);
	}

	@NotNull
	@Override
	protected PsiElement[] create(String newName, PsiDirectory directory) throws Exception {
		Project project = directory.getProject();

		FileTemplateManager fileTemplateManager = FileTemplateManager.getInstance();
		FileTemplate template = fileTemplateManager.getInternalTemplate(JCHFileTemplateProvider.SOLUTION_TEMPLATE);
		FileTemplate bodyTemplate = fileTemplateManager.getCodeTemplate(JCHFileTemplateProvider.SOLUTION_BODY_TEMPLATE_PREFIX + bodyTemplateName + ".java");

		Properties properties = fileTemplateManager.getDefaultProperties();
		properties.setProperty("INPUT_READER", JCHConfiguration.getInstance(project).getState().inputReaderClass);
		properties.setProperty("SOLUTION_CONFIG", "@" + SolutionConfig.class.getName() + "(\ninput=\"" + inputSource + "\", output=\"" + outputSource + "\",\ntests = @" + Tests.class.getName() + "({})\n)");
		properties.setProperty("BODY", bodyTemplate.getText(properties));

		PsiClass createdClass = (PsiClass)FileTemplateUtil.createFromTemplate(template, newName, properties, directory);

		JavaCodeStyleManager.getInstance(project).shortenClassReferences(createdClass);
		CodeStyleManager.getInstance(project).reformat(createdClass);

		return new PsiElement[] {createdClass};
	}

	@Override
	protected String getErrorTitle() {
	  return "Cannot Create Solution";
	}

	@Override
	protected String getCommandName() {
	  return "Create Solution";
	}

	@Override
	protected String getActionName(PsiDirectory directory, String newName) {
		return "Creating solution " + newName;
	}

	private String[] getSolutionBodyTemplateNames() {
		ArrayList<String> results = new ArrayList<String>();
		for (FileTemplate template : FileTemplateManager.getInstance().getAllCodeTemplates()) {
			String name = template.getName();
			if (name.startsWith(JCHFileTemplateProvider.SOLUTION_BODY_TEMPLATE_PREFIX)) {
				results.add(name.substring(JCHFileTemplateProvider.SOLUTION_BODY_TEMPLATE_PREFIX.length()));
			}
		}
		return results.toArray(new String[results.size()]);
	}

	private class MyDialog extends DialogWrapper {
		private JPanel myTopPanel;
		private JTextField mySolutionNameTextField;
		private JComboBox inputComboBox;
		private JTextField inputTextField;
		private JComboBox outputComboBox;
		private JTextField outputTextField;
		private JComboBox bodyTemplateComboBox;

		private final MyInputValidator myValidator;

		private static final String STDIN = "Standard input";
		private static final String STDOUT = "Standard output";
		private static final String NAME_IN = "<name>.in";
		private static final String NAME_OUT = "<name>.out";
		private static final String CUSTOM_FILE = "Custom file";

		public MyDialog(final Project project, final MyInputValidator validator) {
			super(project, true);
			myValidator = validator;
			init();
			setTitle("New Solution");

			inputComboBox.setModel(new DefaultComboBoxModel(new String[]{STDIN, NAME_IN, CUSTOM_FILE}));
			outputComboBox.setModel(new DefaultComboBoxModel(new String[]{STDOUT, NAME_OUT, CUSTOM_FILE}));

			bodyTemplateComboBox.setModel(new DefaultComboBoxModel(getSolutionBodyTemplateNames()));
		}

		@Override
		protected JComponent createCenterPanel() {
			return myTopPanel;
		}

		@Override
		public JComponent getPreferredFocusedComponent() {
			return mySolutionNameTextField;
		}

		@Override
		protected void doOKAction() {
			final String inputString = mySolutionNameTextField.getText().trim();

			inputSource = inputComboBox.getSelectedItem().equals(STDIN) ? SolutionConfig.STANDARD_INPUT :
					inputComboBox.getSelectedItem().equals(NAME_IN) ? inputString + ".in" : inputTextField.getText();
			outputSource = outputComboBox.getSelectedItem().equals(STDOUT) ? SolutionConfig.STANDARD_OUTPUT :
					outputComboBox.getSelectedItem().equals(NAME_OUT) ? inputString + ".out" : outputTextField.getText();

			bodyTemplateName = (String)bodyTemplateComboBox.getSelectedItem();

			if (myValidator.checkInput(inputString) && myValidator.canClose(inputString)) {
				close(OK_EXIT_CODE);
			}
		}
	}
}
